#include<stdio.h>
#include<Arcroll.h>
//#include<Mesh/Mesh.h>
#include<Mesh_IO/Mesh_IO.h>
#include<Mesh/libcell_iterator.h>
#include<Algorithm/subdivision_of_polygon.h>

#include<directories_and_files.h>


#include<libcell_macros.h>

static inline int is_file_obj(char* file)
{
    int len=strlen(file);
    if(file[len-1]=='j'&&file[len-2]=='b'&&file[len-3]=='o'&&file[len-4]=='.')
    {
        return 1;
    }  
    return 0;
}

static inline void swap(double* values,int left,int right)
{
    double temp=values[left];
    values[left]=values[right];
    values[right]=temp;
}

static void sort_double_value(double* values,int left,int right)
{
    if(left>=right)
    {
        return;
    }
    int m; 
    m = left;  
    for (int i=left+1;i<=right;i++)
    {
        if(values[i]<values[left])  
        { 
            swap(values,++m,i);
        }  
    }   
    swap(values,left,m);  
    sort_double_value(values,left,m-1);  
    sort_double_value(values,m+1,right);
}

static inline  int point_is_in_triangle(double *p1,double * p2,double* p3,double *p)
{
    double t1[3]={p[0]-p1[0],p[1]-p1[1],p[2]-p1[2]};
    double t2[3]={p[0]-p2[0],p[1]-p2[1],p[2]-p2[2]};
    double t3[3]={p[0]-p3[0],p[1]-p3[1],p[2]-p3[2]};
    double* n1=out_product(t1,t2);
    double* n2=out_product(t2,t3);
    double* n3=out_product(t3,t1);
    int re=0;
    if(inner_product(n1,n2,3)>0&&inner_product(n1,n3,3)>0 )
    {
        re= 1;
    }
    SAFE_FREE(n1);SAFE_FREE(n2);SAFE_FREE(n3);
    return re;
}

int is_point_in_area(double* p, double**ps,int len,int**subs)
{
    for(int i=0;i<len-2;i++)
    {
        if(point_is_in_triangle(ps[subs[i][0]],ps[subs[i][1]],ps[subs[i][2]],p))
        {
            return 1;
        }   
    }
    return 0;
}   
static inline int is_point_in_quad(double *p,double**ps)
{
    if(p[0]<=ps[0][0]||p[0]>=ps[1][0]||p[1]<=ps[1][1]||p[1]>=ps[2][1])
    {
        return 0;
    } 
    return 1;
}

void filled_area_pixels_data(double**data,int ** data_mark, double**ps,int len,Mesh* m)
{
    int size=150;
    double stepx=(ps[1][0]-ps[0][0])/(double)size,stepy=(ps[2][1]-ps[1][1])/(double)size;
    for(auto vit=m->v_begin(m);vit!=m->v_end(m);vit++)
    {
        if(is_point_in_quad(quote(vit)->point,ps))
        {
            int i=(int)((quote(vit)->point[0]-ps[0][0])/stepx),j= ((quote(vit)->point[1]-ps[0][1])/stepy);
            i=((i<0)?0:(i>=size?(size-1):i));
            j=((j<0)?0:(j>=size?(size-1):j)); 
            if(data_mark[i][j]==-1)
            {
                if(quote(vit)->point[2]>data[i][j])
                {
                    data[i][j]=quote(vit)->point[2];
                }
            }
            else
            {
                data_mark[i][j]=-1;
                data[i][j]=quote(vit)->point[2];
            }
        } 
    }
}

void filled_area_pixels_data1(double**data,int ** data_mark, double**ps,int len,char* path)
{
    int count=0;
    char** result=search_dir_files(path,&count);

    char obj_path[300]={0};
    for(int i=0;i<count;i++)
    {
        if(!is_file_obj(result[i]))
        {
            continue;
        } 
        memset(obj_path,0,sizeof(char)*300);
        strcat(obj_path,path);strcat(obj_path,"/");strcat(obj_path,result[i]);
        
        printf("%s \n", obj_path);
        Mesh mesh;
        Mesh_init(&mesh);
        _ReadObj_(&mesh,obj_path);
        filled_area_pixels_data(data,data_mark,ps,len,&mesh);
        Mesh_free(&mesh);
    } 
    for(int i=0;i<count;i++)
    {
        free(result[i]);
    }  
    free(result);
}

int get_layers(double**data,int**mark_data,int layers,double min_h,double max_h )
{
    int size=150;
    double hundr[400]={0};int hundr_len=0; 
    int mark=0; 
    for(int i=0;i<size;i++)
    {
        for(int j=0;j<size;j++)
        {
            if(mark_data[i][j]==-1)
            {
                if(hundr_len<400)
                {
                    if(data[i][j]>-30.0&&mark<200)
                    {  
                        mark++;
                    }
                    else
                    {
                        hundr[hundr_len]=data[i][j];
                        sort_double_value(hundr,0,hundr_len);
                        hundr_len++;
                    }      
                }
                else
                {
                    if(data[i][j]>hundr[0])
                    {
                        if(data[i][j]>-30.0&&mark<200)
                        {
                            mark++;
                        }
                        else
                        {
                            hundr[0]=data[i][j];
                            sort_double_value(hundr,0,399);
                        }
                            
                       
                    } 
                }
            }
        }
    } 
    double sum=0;
    for(int i=0;i<hundr_len-350;i++)
    {
        printf("%lf\n",hundr[i]);
        sum+=hundr[i];
    }  
    if(hundr_len-350>0)
    {
        sum/=(double)(hundr_len-350);
    }
    printf("sumsda : %lf\n",sum);
    if(sum<= min_h)
    {
        return 0;
    }
    else if(sum>=max_h)
    {
        return layers;
    }
    else
    {
        return (int)((sum-min_h+0.00001)*layers/(max_h-min_h));
    }
    return 0;
}



double test_analyze_max_height_of_one_mesh(double**ps,int len,int** subs,Mesh* m)
{ 
    double re=0;int mark=0;
    double p[3]={0};
    double hundr[2000]={0};int hundr_len=0;
    for(auto vit=m->v_begin(m);vit!=m->v_end(m);vit++)
    {
        p[0]=quote(vit)->point[0];p[1]=quote(vit)->point[1];
        if(is_point_in_area(p,ps,len,subs))
        {
            // if(quote(vit)->point[2]>-35)
            // {
            //     printf("%lf %lf %lf\n",quote(vit)->point[0],quote(vit)->point[1],quote(vit)->point[2]);
            // }
            if(hundr_len<2000)
            {
               
                hundr[hundr_len]=quote(vit)->point[2];
                sort_double_value(hundr,0,hundr_len);
                hundr_len++;
            }
            else
            {
                if(quote(vit)->point[2]>hundr[0])
                {
                    hundr[0]=quote(vit)->point[2];
                    sort_double_value(hundr,0,1999);
                } 
            }
            // if(mark==0|| quote(vit)->point[2]>re)
            // {
            //     re= quote(vit)->point[2];
            //     mark=1;
            // }
        }
    }
    for(int i=0;i<hundr_len-1500;i++)
    {
        re+= hundr[i];
        //printf("%lf\n",hundr[i]);
    }
    if(hundr_len-1500>0)
    {
        re/=(double)(hundr_len-1500);
    }

    return re;
}


double test_analyze_max_height_of_one_dir(double**ps,int len,int** subs,char* path)
{
    // char path[]="D:/siliang/data/A2/A2-mesh/A2-mesh-1230-register";
    int count=0;
    char** result=search_dir_files(path,&count);
    printf("%d\n",count);
    char obj_path[300]={0};
    double re=0;int mark=0;
    for(int i=0;i<count;i++)
    {
        if(!is_file_obj(result[i]))
        {
            continue;
        } 
        memset(obj_path,0,sizeof(char)*300);
        strcat(obj_path,path);strcat(obj_path,"/");strcat(obj_path,result[i]);
        
        printf("%s \n", obj_path);
        Mesh mesh;
        Mesh_init(&mesh);
        _ReadObj_(&mesh,obj_path);
        double temp=test_analyze_max_height_of_one_mesh(ps,len,subs,&mesh);
        if(temp!=0)
        {
            re+=temp;
            mark++;
        }
        printf("height:%lf\n",temp);
        // if(mark==0||temp>re)
        // {
        //     re=temp;
        // }
        Mesh_free(&mesh);
    }
  
    for(int i=0;i<count;i++)
    {
        free(result[i]);
    }
    free(result); 
    if(mark>0)
    {
        re/=(double)mark;
    }
    return re;
}


double test(char* path,double **ps,int len )
{
    int**subs=(int**)malloc(sizeof(int*)*(len-2));
    for(int i=0;i<len-2;i++)
    {
        subs[i]=(int*)malloc(sizeof(int)*3);
        memset(subs[i],0,sizeof(int)*3);
    }
    optimization_subdivision_of_polygon(ps,len,subs);
    // Mesh mesh;
    // Meh_init(&mesh);
    // _ReadObj_(&mesh,"D:/siliang/data/A2/A2-mesh/A2-mesh-1230-register/texture_ABA.obj");
    
    double re=test_analyze_max_height_of_one_dir(ps,len,subs,path);  
    
    for(int i=0;i<len-2;i++)
    {
        free(subs[i]);
    }
    free(subs);
    return re;
}
//
//在bim_path区域下的楼层高度
int test1(char* obj_path,char * bim_path)
{
    char boundary_file[300]={0};
    strcat(boundary_file,bim_path);
    strcat(boundary_file,"/boundary.txt");


    char height_file[300]={0};
    strcat(height_file,bim_path);
    strcat(height_file,"/height_info.txt");

#ifdef _WIN32
    FILE *infile;
    fopen_s(&infile,height_file,"r");
#else
    FILE *infile=fopen(height_file,"r");
#endif
    if(!infile)
    {
        printf("cant't open this file\r\n");
        return 0;
    }
    fseek(infile,0,SEEK_SET);

    char str_temp[100];
    fscanf(infile,"%s", str_temp);
    int layers=0;
    fscanf(infile,"%d",&layers);

    printf("%s %d\n", str_temp,layers);
    fscanf(infile,"%s",str_temp);
    double min_h=0,max_h=0;
    fscanf(infile,"%lf %lf",&min_h,&max_h);
    printf("height:%lf %lf\n",min_h,max_h);
    fclose(infile);
#ifdef _WIN32
    fopen_s(&infile,boundary_file,"r");
#else
    infile=fopen(boundary_file,"r");
#endif
    if(!infile)
    {
        printf("cant't open this file\r\n");
        return 0;
    }
    fseek(infile,0,SEEK_SET);
    double **ps=(double**)malloc(sizeof(double*)*4);
    for(int i=0;i<4;i++)
    {
        ps[i]=(double*)malloc(sizeof(double)*3);
        memset(ps[i],0,sizeof(double)*3);
        for(int j=0;j<2;j++)
        {
            fscanf(infile,"%lf",&ps[i][j] );
            printf("%lf ",ps[i][j]); 
        }
        printf("\n");
    }

    fclose(infile);
    double obj_height= test(obj_path,ps,4);

    printf("obj_height:%lf\n",obj_height);
    //printf("%lf\n", ((20.4)*layers/(max_h-min_h)));
    if(obj_height<= min_h)
    {
        return 0;
    }else if(obj_height>=max_h)
    {
        return layers;
    }
    else
    {
        return (int)((obj_height-min_h+0.00001)*layers/(max_h-min_h)); 
    }
    return 0;
}
void test_viewer(double**data,int**mark_data,double **ps)
{
    int size=150;
    Viewer_World_Manager vwm;
    viewer_world_manager_init(&vwm);
    Viewer_World *vw=vwm.create_world(&vwm,NULL);
    add_default_somethings(vw);
    Node* n=vw->create_something(vw,"Points");

    Viewer_Something*vs=(Viewer_Something*)(n->value);
    Viewer_Points*vp =(Viewer_Points*)(vs->evolution);
    vp->Data_rows=size*size;
    vp->Data=(float*)malloc(sizeof(float)*3*vp->Data_rows);

   // vp->color=(float*)malloc(sizeof(float)*4*vp->Data_rows);

    vp->pointsize=12.0; 
    double temp_x=0,temp_y=0;
    double stepx=(ps[1][0]-ps[0][0])/(double)size,stepy=(ps[2][1]-ps[1][1])/(double)size;
    int num=0; 
    for(int i=0;i<size;i++)
    {
        temp_x=(i+0.5)*stepx+ps[0][0];
        for(int j=0;j<size;j++)
        {
            if(mark_data[i][j]==-1)
            {
                temp_y=(j+0.5)*stepy+ps[0][1];
                vp->Data[num*3+0]=temp_x;vp->Data[num*3+1]=temp_y;vp->Data[num*3+2]=data[i][j];
                num++;
            }
        }
    } 
    printf("num:%d\n",num);
    vp->Data_rows=num;
    vp->set_color(vp,1.0,0.7,0.6,1.0);

    free_node(n); 
    Viewer_Opengl_Interpreter voi;
    viewer_opengl_interpreter_initn(&voi,&vwm);
    voi.interpreter(&voi);

    viewer_opengl_interpreter_free(&voi);
    viewer_world_manager_free(&vwm);    

}
//在bim_path区域下的楼层高度
int test2(char* obj_path,char * bim_path)
{
    printf("test2\n");

    int re=0;
    char boundary_file[300]={0};
    strcat(boundary_file,bim_path);
    strcat(boundary_file,"/boundary.txt");

    char height_file[300]={0};
    strcat(height_file,bim_path);
    strcat(height_file,"/height_info.txt");

#ifdef _WIN32
    FILE *infile;
    fopen_s(&infile,height_file,"r");
#else
    FILE *infile=fopen(height_file,"r");
#endif
    if(!infile)
    {
        printf("cant't open this file\r\n");
        return 0;
    }
    fseek(infile,0,SEEK_SET);

    char str_temp[100];
    fscanf(infile,"%s", str_temp);
    int layers=0;
    fscanf(infile,"%d",&layers);

    printf("%s %d\n", str_temp,layers);
    fscanf(infile,"%s",str_temp);
    double min_h=0,max_h=0;
    fscanf(infile,"%lf %lf",&min_h,&max_h);
    printf("height:%lf %lf\n",min_h,max_h);
    fclose(infile);
#ifdef _WIN32
    fopen_s(&infile,boundary_file,"r");
#else
    infile=fopen(boundary_file,"r");
#endif
    if(!infile)
    {
        printf("cant't open this file\r\n");
        return 0;
    }
    fseek(infile,0,SEEK_SET);
    double **ps=(double**)malloc(sizeof(double*)*4);
    for(int i=0;i<4;i++)
    {
        ps[i]=(double*)malloc(sizeof(double)*3);
        memset(ps[i],0,sizeof(double)*3);
        for(int j=0;j<2;j++)
        {
            fscanf(infile,"%lf",&ps[i][j] );
            printf("%lf ",ps[i][j]); 
        }
        printf("\n");
    }
    fclose(infile);
    int size=150;
    double **data=(double**)malloc(sizeof(double*)*size);
    int ** mark_data=(int**)malloc(sizeof(int*)*size);
    for(int i=0;i<size;i++)
    {
        data[i]=(double*)malloc(sizeof(double)*size);
        memset(data[i],0,sizeof(double)*size);
        mark_data[i]=(int*)malloc(sizeof(int)*size);
        memset(mark_data[i],0,sizeof(int)*size);
    }
    filled_area_pixels_data1(data,mark_data, ps,4,obj_path);

    //test_viewer(data,mark_data,ps);

    re= get_layers(data,mark_data,layers,min_h,max_h); 


    printf("layer:%d\n",re);
    for(int i=0;i<4;i++)
    {
        SAFE_FREE(ps[i]);
    }
    SAFE_FREE(ps);
    for(int i=0;i<size;i++)
    {
        SAFE_FREE(data[i]);
        SAFE_FREE(mark_data[i]);
    } 

    SAFE_FREE(data);SAFE_FREE(mark_data);

    return re;
}
void test3(char* date_mesh,char* bim_path)
{
    char mesh_path[300]={0};
    strcat(mesh_path,"D:/siliang/data/A2/A2-mesh/");
    strcat(mesh_path,date_mesh);
    printf("%s\n",mesh_path);
    char bim_path1[300]={0};
    int count=0;
    char** result=search_dir_files(bim_path,&count);
    
    for(int i=0;i<count;i++)
    {
        memset(bim_path1,0,sizeof(char)*300);
        strcat(bim_path1,bim_path);strcat(bim_path1,"/");
        int len= strlen(result[i]);
        if(result[i][len-1]=='#')
        {
            strcat(bim_path1,result[i]);

            int layer=test2(mesh_path,bim_path1); 

            strcat(bim_path1,"/layers_info.txt");
#ifdef _WIN32
            FILE *outfile;
            fopen_s(&outfile,bim_path1,"w");
#else
            FILE *outfile=fopen(bim_path1,"w");
#endif 
            fprintf(outfile,date_mesh);
            fprintf(outfile,"\n");
            fprintf(outfile,result[i]);
            fprintf(outfile,"\n%d\n",layer);
            printf("%s\n",bim_path1);
            fclose(outfile);
        }   
    } 

    for(int i=0;i<count;i++)
    {
        free(result[i]);
    }
    free(result);
}


int main()
{
    // int count=0;
    char path[]="D:/siliang/data/A2/A2-mesh/A2-mesh-1230-register";
    // char** result=search_dir_files(path,&count);
    // printf("%d\n",count);
    // for(int i=0;i<count;i++)
    // {
    //     printf("%s \n", result[i]);
    //     free(result[i]);
    // } 
    // free(result);
    //test();
    double** ps=(double**)malloc(sizeof(double*)*4);
    for(int i=0;i<4;i++)
    {
        ps[i]=(double*)malloc(sizeof(double)*3);
        memset(ps[i],0,sizeof(double)*3); 
    }
    ps[0][0]= 242.0626901552896 ; ps[0][1]= 62.86711422447115 ; 
    ps[1][0]= 366.8631508538383; ps[1][1]= 62.86711422447115 ; 
    ps[2][0]= 366.8631508538383 ; ps[2][1]= 96.26920376578346 ; 
    ps[3][0]= 242.0626901552896 ; ps[3][1]= 96.26920376578346 ; 
    //test(path,ps,4);
    char bim_path[]="D:/siliang/data/A2/A2-bim/A2-bim-align/3#";


    //int layer=test1(path,bim_path);
    //int layer=test2(path,bim_path);
    test3("A2-mesh-1230-register","D:/siliang/data/A2/A2-bim/A2-bim-align");
     
    //printf("layer:%d\n",layer);



    printf("end\n");

    return 0;
}
